package cn.iocoder.yudao.module.iot.gateway.protocol.tcp;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.config.TcpProtocolConfig;
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.manager.IotTcpConnectionManager;
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router.IotTcpUpstreamHandler;
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router.handler.ProtocolHandlerRegistry;
import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
import io.vertx.core.Vertx;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.NetServerOptions;
import io.vertx.core.net.PemKeyCertOptions;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils.generateServerId;

/**
 * IoT 网关 TCP 协议: 接收设备上行消息
 *
 * @author 芋道源码
 */
@Slf4j
public class IotTcpUpstreamProtocol {

    private final IotGatewayProperties.TcpProperties tcpProperties;

    private final IotDeviceService deviceService;

    private final IotDeviceMessageService messageService;

    private final IotTcpConnectionManager connectionManager;

    private final Vertx vertx;

    @Getter
    private Map<Integer, String> serverIdMap = MapUtil.newHashMap();


    // 存储所有启动的服务器实例
    private final List<NetServer> servers = new ArrayList<>();

    public IotTcpUpstreamProtocol(IotGatewayProperties.TcpProperties tcpProperties,
                                  IotDeviceService deviceService,
                                  IotDeviceMessageService messageService,
                                  IotTcpConnectionManager connectionManager,
                                  Vertx vertx) {
        this.tcpProperties = tcpProperties;
        this.deviceService = deviceService;
        this.messageService = messageService;
        this.connectionManager = connectionManager;
        this.vertx = vertx;
        this.serverIdMap = initServerIdMap();
    }

    private Map<Integer, String> initServerIdMap() {
        List<TcpProtocolConfig> protocols = tcpProperties.getProtocols();
        if (CollUtil.isEmpty(protocols)) {
            return MapUtil.newHashMap();
        }
        return protocols.stream()
                .filter(TcpProtocolConfig::getEnabled)
                .collect(Collectors.toMap(TcpProtocolConfig::getPort, x -> generateServerId(x.getPort())));
    }

    @PostConstruct
    public void start() {
        List<TcpProtocolConfig> protocols = tcpProperties.getProtocols();

        if (CollUtil.isEmpty(protocols)) {
            return;
        }

        // 启动自定义协议服务器
        for (TcpProtocolConfig config : protocols) {
            if (BooleanUtil.isFalse(config.getEnabled())) {
                continue;
            }
            startServer(config);
        }
    }


    private void startServer(TcpProtocolConfig config) {
        Integer port = config.getPort();
        String protocolType = config.getProtocolType();
        try {
            // 创建服务器选项
            NetServerOptions options = new NetServerOptions()
                    .setPort(port)
                    .setTcpKeepAlive(true)
                    .setTcpNoDelay(true)
                    .setReuseAddress(true);

            // 配置 SSL（如果启用）
            if (Boolean.TRUE.equals(config.getSslEnabled())) {
                PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions()
                        .setKeyPath(config.getSslKeyPath())
                        .setCertPath(config.getSslCertPath());
                options.setSsl(true).setKeyCertOptions(pemKeyCertOptions);
            }

            // 创建服务器并设置连接处理器
            NetServer server = vertx.createNetServer(options);
            server.connectHandler(socket -> {
                // 根据协议类型创建相应的处理器
                IotTcpUpstreamHandler handler = new IotTcpUpstreamHandler(
                        this,messageService, deviceService, connectionManager, config);
                handler.handle(socket);
            });

            // 启动服务器
            server.listen().result();
            servers.add(server);
            log.info("[start][IoT 网关 TCP 协议启动成功, 端口: {}, 协议类型: {}]", port, protocolType);
        } catch (Exception e) {
            log.error("[start][IoT 网关 TCP 协议启动失败, 端口: {}, 协议类型: {}]", port, protocolType, e);
            throw new RuntimeException("TCP协议启动失败, 端口: " + port + ", 协议类型: " + protocolType, e);
        }
    }

    @PreDestroy
    public void stop() {
        // 关闭所有服务器实例
        for (NetServer server : servers) {
            try {
                server.close().result();
            } catch (Exception e) {
                log.error("[stop][IoT 网关 TCP 协议停止失败]", e);
            }
        }
        log.info("[stop][所有 IoT 网关 TCP 协议已停止]");
    }
}